package javaeSE;
// 类 与继承
public class Extends {
        public static void main(String[] args) {

            Person person1 = new Person("wf",20,1001,"人的私有属性");
            //Person person12 =(Person) person1.clone();
            System.out.println(person1.id);
            System.out.println(person1.name);
            System.out.println(person1.age);
            System.out.println(person1.getName());
            // person1.setName("wfwf");
            // System.out.println(person1.getName());
            person1.setprivateItem("set改变人的私有属性");
            System.out.println(person1.getprivateItem());
            person1.eat();
            person1.makeMoney(200);

            /* 类的私有方法无法通过实例访问  但是可以被其他成员方法调用
               person1.privateway();   */

            /*person1.privateway();*/
            System.out.println("-------------");
            // 子类
            Student stu1 = new Student("stu1Name",21,10001,10002,"阳光");
            /*
             Student stu2 = stu1;这个情况跟js是一样的 指向同一个堆
             new 与 = 的区别
             */
            System.out.println(stu1.name);
            System.out.println(stu1.toString());
            stu1.eat();
            stu1.zi();
            System.out.println("子类也会赚钱");
            stu1.makeMoney(200);
            System.out.println("-------------");
            Student[] stus = Student.createStudent();
            for (int i = 0; i < stus.length; i++) {
                System.out.println(stus[i].toString());
            }

        }
    }

// java 类的基础及其应用(封装与继承)
    class Person {
    // java私有属性不能通过 .访问和赋值,需要给对应的set get方法获取与修改
    // 这些成员属性 普通方法可以访问的到它
        public int id;
        public String name ;
        public int age ;

        private String privateItem;
        // 空参构造器要习惯性的写好上
        public Person(){
            // 默认构造函数
            System.out.println("我是默认构造函数");
        }
        // 构造方法1
        public Person(String name, int age, int id, String privateItem){
            // 可以调其他构造函数
            this();

            //最好 写this
            this.id = id;
            this.age = age;
            this.name = name;
            this.privateItem = privateItem;
        }
        // 构造方法2
        public Person(String name, int age, int id){
            this.id = id;
            this.age = age;
            this.name = name;
        }

        public void setName(String name) {
            this.name = name ;
        }
        public String getName() {
            return this.name ;
        }
        public void setprivateItem(String privateItem) {
            this.privateItem = privateItem ;
        }
        public String getprivateItem() {
            return this.privateItem ;
        }
        public void eat(){
            System.out.println("人会吃饭");
        }
        public void makeMoney(int money){
            System.out.println("人会赚钱"+money);
            this.privateway("test");
        }

        private void privateway(String privateItem){
            this.privateItem = privateItem ;
            System.out.println("私有方法"+this.privateItem);
        }

    }

    //  子类拥有父类 private 的属性、方法  (私有属性继承但不能通过.调用 用get set) 但不能直接调
    class Student extends Person{
        // 子类的属性
        // 继承完之后不要再写一遍父类的属性
        public int stuId;
        private String school = "阳光中学";
        public Student(){
            // 子类无参构造函数
        }
        //子类构造器特点:
        //因为子类只继承了父类的成员方法, 子类没有继承到父类的构造器,但是要求子类必须调用父类构造器
        // 这里怎么写，就会去父类怎么找对应的构造函数(形参必须一致)
        // 访问父类的属性: super.属性名=属性值
        // 访问父类的方法: super.方法(实参列表)
        public Student(String name, int age, int id,int stuId,String school){
            // super必须要在第一行
            // super(name,age,id);
            // 等价写法
            super.name =name;
            super.age=age;
            super.id=id;
            this.stuId = stuId;
            this.school = school;
        }

        public void setSchool(String school) {
            this.school = school;
        }
        public String getSchool() {
            return this.school;
        }
        public void zi(){
            // 子类方法中调用父类方法
            super.eat();
            System.out.println("我是子类方法");
        }
        //创建学生
        public static Student[] createStudent(){
           Student[] stus = new Student[10];
            for (int i = 0;i<stus.length;i++){
                // 没有初始化对象
                stus[i] = new Student();
                stus[i].id = i;
                stus[i].stuId = i;
                stus[i].age =(int)(Math.random()*100);
                stus[i].name = "xiaomi";
            }
            return stus;
        }
        // 这些必须是实例调用
        public void printStudent(Student [] stus){
            for (int i = 0; i < stus.length; i++) {
                System.out.println(stus[i].toString());
            }
        }
        // 这些必须是实例调用  交换的是学生对象
        public void sortStudent(Student [] stus){
            for(int i = 0;i < stus.length - 1;i++){
                for(int j = 0;j < stus.length - 1 - i;j++){
                    if(stus[j].id > stus[j + 1].id){
                        //如果需要换序，交换的是数组的元素：Student对象！！！
                        Student temp = stus[j];
                        stus[j] = stus[j + 1];
                        stus[j + 1] = temp;
                    }
                }
            }
            System.out.println(stus.toString());
        }
        @Override
        public void eat() {
            // 继承(调用)父类方法  或者直接舍弃重写
            super.eat();
            //添加父类方法里没有的内容
            System.out.println("添加父类eat方法中没有的东西");
        }

        @Override
        public String toString() {
            return "Student{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", age=" + age +
                    ", stuId=" + stuId +
                    ", school='" + school + '\'' +
                    '}';
        }
    }
/*
  子类重写父类方法的重写规则
        参数列表与被重写方法的参数列表必须完全相同。
        返回类型与被重写方法的返回类型可以不相同(void要相同)，但是必须是父类返回值的派生(子)类。
        访问权限不能比父类中被重写的方法的访问权限更低。例如：如果父类的一个方法被声明为 public，那么在子类中重写该方法就不能声明为 protected。
        父类的成员方法只能被它的子类重写。
        声明为private, final,static的方法不能被重写（能被继承）。后者能够被再次声明

        子类和父类在同一个包中，那么子类可以重写父类所有方法，除了声明为 private 和 final 的方法。
        子类和父类不在同一个包中，那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法。

        重写的方法能够抛出任何非强制异常，无论被重写的方法是否抛出异常。
        但是，重写的方法不能抛出新的强制性异常，或者比被重写方法声明的更广泛的强制性异常，反之则可以。
        构造方法不能被重写。
        */
